package com.csu.cphone.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import redis.clients.jedis.GeoRadiusResponse;
import redis.clients.jedis.GeoUnit;
import redis.clients.jedis.params.geo.GeoRadiusParam;

import com.csu.common.exception.WebException;
import com.csu.common.sms.SMSSender;
import com.csu.common.utils.AuthCodeUtil;
import com.csu.common.utils.PasswdUtil;
import com.csu.common.utils.RedisUtil;
import com.csu.common.vo.WxAccessTokenVo;
import com.csu.common.wx.WxAuthorizeHelper;
import com.csu.cphone.constants.ErrorCode;
import com.csu.cphone.constants.RedisKey;
import com.csu.cphone.dao.CustomerMapper;
import com.csu.cphone.dao.ProducerMapper;
import com.csu.cphone.pojo.CustomerPojo;
import com.csu.cphone.pojo.ProducerPojo;
import com.csu.cphone.service.UserService;
import com.csu.cphone.vo.OrderMessageVo;

/**
 * @项目名称：cphone
 * @类名称：UserServiceImpl
 * @类描述：
 * @创建人：Tangc
 * @创建时间：2017年9月11日 下午5:43:46
 * @company:
 */
@Service
public class UserServiceImpl implements UserService
{

    private static final Logger logger = Logger.getLogger(UserServiceImpl.class);

    @Autowired
    private CustomerMapper customerMapper;

    @Autowired
    private ProducerMapper producerMapper;

    /**
     * @see com.csu.cphone.service.UserService#customerSign(java.lang.String,
     *      java.lang.String, java.lang.String, java.lang.String)
     */
    @Override
    public CustomerPojo customerSign(String wxOpenid, String number, String password, String name)
    {
        String passwordMd5 = PasswdUtil.md5Passwd(password);
        CustomerPojo customer = new CustomerPojo();
        customer.setName(name);
        customer.setNumber(number);
        customer.setPasswd(passwordMd5);
        customer.setWxOpenid(wxOpenid);
        customerMapper.insert(customer);
        return customer;
    }

    /**
     * @throws WebException
     * @see com.csu.cphone.service.UserService#customerLogin(java.lang.String,
     *      java.lang.String, java.lang.String)
     */
    @Override
    public CustomerPojo customerLogin(String wxOpenid, String number, String password) throws WebException
    {
        CustomerPojo customer;
        if (number == null || StringUtils.isEmpty(number))
        {
            customer = customerMapper.selectByWxOpenid(wxOpenid);
        }
        else
        {
            customer = customerMapper.selectByNumber(number);
        }

        if (customer == null)
        {
            throw new WebException(ErrorCode.UserNullCode, ErrorCode.UserNullMessgae);
        }
        if (!PasswdUtil.checkPasswd(password, customer.getPasswd()))
        {
            throw new WebException(ErrorCode.PasswdErrorCode, ErrorCode.PasswdErrorMessgae);
        }

        return customer;
    }

    /**
     * @throws WebException
     * @see com.csu.cphone.service.UserService#producerLogin(java.lang.String,
     *      java.lang.String)
     */
    @Override
    public ProducerPojo producerLogin(String number, String password) throws WebException
    {
        ProducerPojo producer = producerMapper.selectByNumber(number);

        if (producer == null)
        {
            throw new WebException(ErrorCode.UserNullCode, ErrorCode.UserNullMessgae);
        }
        if (!PasswdUtil.checkPasswd(password, producer.getPasswd()))
        {
            throw new WebException(ErrorCode.PasswdErrorCode, ErrorCode.PasswdErrorMessgae);
        }

        return producer;
    }

    /**
     * @see com.csu.cphone.service.UserService#checkAuthCode(String, String)
     */
    @Override
    public boolean checkAuthCode(String number, String authCode) throws WebException
    {
        String key = RedisKey.Sign_Auth_Code + number;
        String redisCode = RedisUtil.getRedisDb().get(key);
        if (!authCode.equals(redisCode))
        {
            logger.error("验证码校验失败，authCode：" + authCode + "不等于redisCode:" + redisCode);
            throw new WebException(ErrorCode.AuthCodeError, ErrorCode.AuthCodeErrorMessgae);
        }
        return true;
    }

    /**
     * @see com.csu.cphone.service.UserService#sendSignCode(java.lang.String)
     */
    @Override
    public Boolean sendSignCode(String number)
    {
        String key = RedisKey.Sign_Auth_Code + number;
        String authCode = AuthCodeUtil.getCode(4);// 4位验证码
        RedisUtil.getRedisDb().setex(key, RedisKey.Sign_Auth_Code_Time, authCode);
        return SMSSender.sendSMSByType(number, authCode, 0);
    }

    /**
     * @see com.csu.cphone.service.UserService#producerUpload(java.lang.String,
     *      java.lang.Double, java.lang.Double)
     */
    @Override
    public List<OrderMessageVo> producerUpload(String number, Double lat, Double lng, Integer serviceStatus)
    {
        // ProducerPojo producer = producerMapper.selectByNumber(number);
        RedisUtil.getRedisDb().geoadd(getKey(), lng, lat, getMember(number));// 更新地理位置
        RedisUtil.getRedisDb().setex(RedisKey.Online_Status + number, 6 * 60, number);// 保活6分钟
        if (serviceStatus != null)
        {
            // 更新服务状态
            RedisUtil.getRedisDb().set(RedisKey.PRODUCER_SERVICE_STATUS + number, serviceStatus.toString());
        }

        // 查询是否有消息
        List<OrderMessageVo> messages = getMessages(number);
        return messages;
    }

    /**
     * @description
     * @author TangC
     * @date 2017年12月16日 上午10:59:22
     * @return
     */

    private List<OrderMessageVo> getMessages(String number)
    {
        List<OrderMessageVo> result = new ArrayList<OrderMessageVo>();
        List<String> maintain = RedisUtil.getRedisDb().lrange(RedisKey.WAITING_MAINTAIM_ORDER + number, 0, -1);
        List<String> recycle = RedisUtil.getRedisDb().lrange(RedisKey.WAITING_RECYCLE_ORDER + number, 0, -1);
        if (!CollectionUtils.isEmpty(maintain))
        {
            for (String sn : maintain)
            {
                OrderMessageVo message = new OrderMessageVo();
                message.setOrderSn(sn);
                message.setOrderType(1);
                result.add(message);
                RedisUtil.getRedisDb().lrem(RedisKey.WAITING_MAINTAIM_ORDER, 0, sn);
            }
        }
        if (!CollectionUtils.isEmpty(recycle))
        {
            for (String sn : recycle)
            {
                OrderMessageVo message = new OrderMessageVo();
                message.setOrderSn(sn);
                message.setOrderType(2);
                result.add(message);
                RedisUtil.getRedisDb().lrem(RedisKey.WAITING_RECYCLE_ORDER, 0, sn);
            }
        }
        return result;
    }

    /**
     * @description
     * @author TangC
     * @date 2017年12月8日 下午4:32:24
     * @param number
     * @return
     */
    private byte[] getMember(String number)
    {
        if (number == null || number.trim().equals(""))
        {
            return null;
        }
        return number.getBytes();
    }

    /**
     * @description
     * @author TangC
     * @date 2017年12月8日 下午4:31:55
     * @return
     */

    private byte[] getKey()
    {
        String key = RedisKey.PRODUCER_UPLOAD_POSITION;
        return key.getBytes();
    }

    /**
     * @see com.csu.cphone.service.UserService#getServiceStatus(java.lang.String)
     */
    @Override
    public Integer getServiceStatus(String number)
    {
        String status = RedisUtil.getRedisDb().get(RedisKey.PRODUCER_SERVICE_STATUS + number);
        if (status == null)
        {
            return 1;
        }
        return Integer.parseInt(status);
    }

    /**
     * @see com.csu.cphone.service.UserService#getNearProducer(java.lang.Double,
     *      java.lang.Double)
     */
    @Override
    public ProducerPojo getNearProducer(Double lat, Double lng, Integer service)
    {
        ProducerPojo result = null;
        double radius = 100d;
        GeoRadiusParam param = GeoRadiusParam.geoRadiusParam().withDist().sortAscending().count(1);
        List<GeoRadiusResponse> resultList = RedisUtil.getRedisDb().georadius(getKey(), lng, lat, radius, GeoUnit.KM,
                param);
        if (CollectionUtils.isEmpty(resultList))
        {
            resultList = RedisUtil.getRedisDb().georadius(getKey(), lng, lat, radius * 2, GeoUnit.KM, param);
        }
        if (CollectionUtils.isEmpty(resultList))
        {
            return null;
        }
        for (GeoRadiusResponse geoRadiusResponse : resultList)
        {
            String number = geoRadiusResponse.getMemberByString();
            ProducerPojo producer = producerMapper.selectByNumber(number);
            if (producer != null && !StringUtils.isEmpty(producer.getNumber()))
            {
                result = producer;
                break;
            }
        }
        return result;

    }

    /**
     * @see com.csu.cphone.service.UserService#getProducerByNumber(java.lang.String)
     */
    @Override
    public ProducerPojo getProducerByNumber(String number)
    {
        ProducerPojo producer = producerMapper.selectByNumber(number);
        if (producer == null)
        {
            return null;
        }
        return producer;
    }

    /**
     * @throws WebException
     * @see com.csu.cphone.service.UserService#getOpenIdByCode(java.lang.String,
     *      java.lang.String)
     */
    @Override
    public String getOpenIdByCode(String code, String state) throws WebException
    {
        WxAccessTokenVo accessTokenVo = WxAuthorizeHelper.getAccessToken(code);
        return accessTokenVo.getOpenid();
    }

    /**
     * @see com.csu.cphone.service.UserService#updateOpenid(java.lang.String,
     *      java.lang.Integer)
     */
    @Override
    public Integer updateOpenid(String openid, Integer customerId)
    {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("wxOpenid", openid);
        map.put("id", customerId);
        return customerMapper.updateOpenid(map);
    }

    /**
     * @see com.csu.cphone.service.UserService#selectByOpenId(java.lang.String)
     */
    @Override
    public CustomerPojo selectByOpenId(String openid)
    {
        return customerMapper.selectByWxOpenid(openid);
    }
}
